package prj.util;

import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.view.faces.context.AdfFacesContext;
import oracle.binding.OperationBinding;
import oracle.jbo.Transaction;

public class FacesUtils
{
	private static DCBindingContainer bindings;
	
	static
	{
		bindings = (DCBindingContainer) resolveExpression("#{bindings}");
	}
	
	public static Object resolveExpression(String expr)
	{
		return getApplication().createValueBinding(expr).getValue(getContext());
	}
	
	public static DCBindingContainer getBindings()
	{
		return bindings;
	}
	
	// Should not be used internally, because in most cases you want to know
	// that it was invalid, and that is the default behavior of methods using
	// expression. An exception is thrown in these situations which is way more
	// informative then hiding the mistake.
	public static boolean isValidExpression(String expr)
	{
		expr = expr.trim();
		
		return expr.startsWith("#{") && expr.endsWith("}");
	}
	
	public static FacesContext getContext()
	{
		return FacesContext.getCurrentInstance();
	}
	
	public static ExternalContext getExternalContext()
	{
		return getContext().getExternalContext();
	}
	
	public static Application getApplication()
	{
		FacesContext context = FacesContext.getCurrentInstance();

		if (context != null)
		{
			return FacesContext.getCurrentInstance().getApplication();
		}

		ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory("javax.faces.application.ApplicationFactory");

		return applicationFactory.getApplication();
	}
	
	public static Transaction getTransaction()
	{
		return bindings.getDataControl().getApplicationModule().getTransaction();
	}
	
	@SuppressWarnings("unchecked")
	public static void setRequestParam(String name, Object value)
	{
		getExternalContext().getRequestMap().put(name, value);
	}
	
	public static Object getRequestParam(String name)
	{
		return getExternalContext().getRequestMap().get(name);
	}

	@SuppressWarnings("unchecked")
	public static void setSessionParam(String name, Object value)
	{
		getExternalContext().getSessionMap().put(name, value);
	}
	
	public static Object getSessionParam(String name)
	{
		return getExternalContext().getSessionMap().get(name);
	}

	@SuppressWarnings("unchecked")
	public static void setApplicationParam(String name, Object value)
	{
		getExternalContext().getApplicationMap().put(name, value);
	}
	
	public static Object getApplicationParam(String name)
	{
		return getExternalContext().getApplicationMap().get(name);
	}
	
	public static HttpServletRequest getRequest()
	{
		return (HttpServletRequest) getExternalContext().getRequest();
	}
	
	public static HttpServletResponse getResponse()
	{
		return (HttpServletResponse) getExternalContext().getResponse();
	}
	
	@SuppressWarnings("unchecked")
	public static Object invokeMethod(String expr, Class[] paramTypes, Object[] params)
	{
		return getApplication().createMethodBinding(expr, paramTypes).invoke(getContext(), params);
	}
	
	@SuppressWarnings("unchecked")
	public static Object invokeMethod(String expr, Class paramType, Object param)
	{
		return invokeMethod(expr, new Class[]{paramType}, new Object[]{param});
	}
	
	public static Object invokeMethod(String expr)
	{
		return invokeMethod(expr, new Class[0], new Object[0]);
	}
	
	// Invokes a JSF navigation case. Like the "action" attribute does for
	// a command button.
	public static void invokeAction(String action)
	{
		getApplication().getNavigationHandler().handleNavigation(getContext(), null, action);
	}
	
	public static boolean invokeCommit()
	{
		OperationBinding commit = bindings.getOperationBinding("Commit");
		
		commit.execute();
		
		return commit.getErrors().isEmpty();
	}

	public static boolean invokeRollback()
	{
		OperationBinding rollback = bindings.getOperationBinding("Rollback");
		
		rollback.execute();
		
		return rollback.getErrors().isEmpty();
	}
	
	public static void test()
	{
		/*
		// Commit/Rollback and the like.
		List<OperationBinding> operationBindings = bindings.getOperationBindings();
		
		for (OperationBinding b: operationBindings)
		{
			System.out.println(b.getName());
		}
		*/
		/*
		// Everything that is available: #{bindings.*}
		List<ControlBinding> controlBindings = bindings.getControlBindings();
		
		for (ControlBinding b: controlBindings)
		{
			System.out.println(b.getName());
		}
		*/
		/*
		// All executable bindings like iterators.
		List<JUIteratorBinding> executableBindings = bindings.getExecutableBindings();
		
		for (JUIteratorBinding b: executableBindings)
		{
			System.out.println(b.getName());
		}
		*/
		/*
		// Everything that is available: #{bindings.*} and all executable bindings.
		ArrayList<ControlBinding> ctrlBindings = bindings.getCtrlBindingList();
		
		for (ControlBinding b: ctrlBindings)
		{
			System.out.println(b.getName());
		}
		*/
	}
}
